home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Qu.......ke Neue Level
/
KroGer Software GmbH - Qu_ke.iso
/
UTILITY
/
PRG8.ZIP
/
F_WAD2.C
< prev
next >
Wrap
C/C++ Source or Header
|
1996-03-03
|
11KB
|
364 lines
/*
* Copyright (C) 1996 by Raphael Quinet. All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice appear in all
* copies and that both that copyright notice and this permission
* notice appear in supporting documentation. If more than a few
* lines of this code are used in a program which displays a copyright
* notice or credit notice, the following acknowledgment must also be
* displayed on the same screen: "This product includes software
* developed by Raphael Quinet for use in the Quake Editing Utilities
* project." THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR
* IMPLIED WARRANTY.
*
* More information about the QEU project can be found on the WWW:
* "http://www.montefiore.ulg.ac.be/~quinet/games/editing.html" or by
* mail: Raphael Quinet, 9 rue des Martyrs, B-4550 Nandrin, Belgium.
*/
/*
* F_WAD2.C - Read and write Quake WAD2 files.
*/
#include "qeu.h"
#include "q_misc.h"
#include "q_files.h"
#include "f_bitmap.h"
#include "f_wad2.h"
/*
* Read the WAD2 directory into memory. The optional offset to the
* start of the WAD2 file is given in "offset". The number of entries in
* the directory is returned in *dirsize_r.
*/
WAD2DirPtr ReadWAD2Directory(FILE *wadfile, UInt32 offset, UInt16 *dirsize_r)
{
WAD2DirPtr dir;
UInt32 pos, size;
UInt16 max, i;
*dirsize_r = 0;
if (wadfile == NULL)
return NULL;
if ((fseek(wadfile, offset, SEEK_SET) < 0)
|| (ReadMagic(wadfile) != FTYPE_WAD2)
|| (ReadInt32(wadfile, &size) == FALSE)
|| (ReadInt32(wadfile, &pos) == FALSE)
|| (size == 0L)
|| (size > 65535L)
|| (fseek(wadfile, pos, SEEK_SET) < 0))
return NULL;
dir = (WAD2DirPtr)QMalloc(size * sizeof(struct WAD2Directory));
max = (UInt16)size;
for (i = 0; i < max; i++)
{
if (ReadBytes(wadfile, &dir[i], sizeof(struct WAD2Directory)) == FALSE)
{
QFree(dir);
return NULL;
}
dir[i].offset = SwapInt32(dir[i].offset);
dir[i].size = SwapInt32(dir[i].size);
dir[i].dsize = SwapInt32(dir[i].dsize);
}
*dirsize_r = max;
return dir;
}
/*
* Return the index number of the first entry matching "entryname".
* A number greater or equal to dirsize is returned if no match is found.
*/
UInt16 FindWAD2Entry(WAD2DirPtr dir, UInt16 dirsize, char *entryname)
{
UInt16 i;
if (dir == NULL)
ProgError("BUG: Cannot find entry in NULL directory");
for (i = 0; i < dirsize; i++)
if (!strnicmp(dir[i].name, entryname, 16))
return i;
return i;
}
/*
* Print the contents of the WAD2 directory in "outf".
*/
void DumpWAD2Directory(FILE *outf, WAD2DirPtr dir, UInt16 dirsize)
{
UInt16 i;
UInt32 sum;
char buf[17];
if (outf == NULL || dir == NULL || dirsize == 0)
return;
fprintf(outf, "num offset size size type cmpr entry name\n");
fprintf(outf, " (hex) (dec) (dec)\n");
sum = 0L;
for (i = 0; i < dirsize; i++)
{
strncpy(buf, dir[i].name, 16);
buf[16] = '\0';
fprintf(outf, "%3u 0x%08lx %6ld %6ld %c %d %s\n",
i, dir[i].offset, dir[i].size, dir[i].dsize,
dir[i].dtype, dir[i].compression, buf);
sum += dir[i].size;
}
fprintf(outf, "\nTotal size for %3u entries: %7lu bytes.\n", dirsize, sum);
fprintf(outf, "Size of the WAD2 directory: %7lu bytes.\n",
(UInt32)dirsize * (UInt32)sizeof(struct WAD2Directory));
fprintf(outf, "Total (header + data + dir): %7lu bytes.\n",
12L + sum + (UInt32)dirsize * (UInt32)sizeof(struct WAD2Directory));
}
/*
* Extract all entries from a WAD2 file and save them in separate
* files. The files will be saved in the directory "prefixpath". If
* "outf" is not null, progress information will be printed in it.
*/
Bool UnWAD2File(FILE *outf, FILE *wadfile, UInt32 offset, WAD2DirPtr dir,
UInt16 dirsize, UInt16 entrynum, char *prefixpath,
Bool convert)
{
char *newname;
char *p;
FILE *newfile;
FILE *indexfile;
UInt16 i;
UInt32 sum;
BitMap *bmptr;
struct RGB *palptr = NULL;
if (wadfile == NULL || dir == NULL || dirsize == 0)
return FALSE;
if (prefixpath == NULL)
prefixpath = ".";
if (convert == TRUE)
{
for (i = 0; i < dirsize; i++)
if (dir[i].dtype == '@' && !stricmp(dir[i].name, "PALETTE"))
break;
if (i < dirsize)
palptr = ReadPalette256(wadfile, offset + dir[i].offset);
if (palptr == NULL)
return FALSE;
}
newname = (char *)QMalloc(strlen(prefixpath) + 16 + 4 + 2);
strcpy(newname, prefixpath);
p = &newname[strlen(newname) - 1];
#ifdef QEU_DOS
if (*p != '\\')
{
p++;
*p = '\\';
}
#else
if (*p != '/')
{
p++;
*p = '/';
}
#endif
p++;
strcpy(p, QEU_INDEX_FILE);
if (outf != NULL)
fprintf(outf, "Creating index file %s\n", newname);
CreatePathToFile(newname);
indexfile = fopen(newname, "a");
fprintf(indexfile, "BEGIN WAD2\n");
sum = 0L;
for (i = 0; i < dirsize; i++)
{
if (entrynum < dirsize && i != entrynum)
continue; /* horrible trick... */
strcpy(p, dir[i].name);
if (dir[i].dtype == '@')
strcat(p, ".lmp");
else if (dir[i].dtype == 'B')
if (convert == TRUE)
strcat(p, ".bmp");
else
strcat(p, ".pic");
else if (dir[i].dtype == 'E')
if (convert == TRUE)
strcat(p, ".bmp");
else
strcat(p, ".bit");
else
strcat(p, ".xxx");
if (outf != NULL)
fprintf(outf, "Saving %6ld bytes to %s\n", dir[i].size, newname);
CreatePathToFile(newname);
newfile = fopen(newname, "wb");
if (newfile == NULL)
{
fclose(indexfile);
QFree(newname);
return FALSE;
}
/* BMP conversion stuff */
if (convert == TRUE && (dir[i].dtype == 'B' || dir[i].dtype == 'E'))
{
fprintf(indexfile, "+ %s %c #= %s\n", dir[i].name, dir[i].dtype, p);
if (dir[i].dtype == 'E')
{
if (!stricmp(dir[i].name, "CONCHARS"))
bmptr = ReadRawBitMap(wadfile, offset + dir[i].offset,
128, 128);
else if (!stricmp(dir[i].name, "CONBACK"))
bmptr = ReadRawBitMap(wadfile, offset + dir[i].offset,
320, 200);
else
bmptr = NULL;
}
else
bmptr = ReadBitMap(wadfile, offset + dir[i].offset);
if (bmptr == NULL)
{
fclose(newfile);
fclose(indexfile);
QFree(newname);
return FALSE;
}
sum += SaveBMP(newfile, bmptr, palptr);
}
else
{
fprintf(indexfile, "+ %s %c = %s\n", dir[i].name, dir[i].dtype, p);
if ((fseek(wadfile, offset + dir[i].offset, SEEK_SET) < 0)
|| (CopyBytes(newfile, wadfile, dir[i].size) == FALSE))
{
fclose(newfile);
fclose(indexfile);
QFree(newname);
return FALSE;
}
sum += dir[i].size;
}
fclose(newfile);
}
if (outf != NULL && entrynum >= dirsize)
fprintf(outf, "Saved %lu bytes in %u files.\n", sum, dirsize);
fprintf(indexfile, "END WAD2\n");
fclose(indexfile);
QFree(newname);
return TRUE;
}
/* ----------------------------------------------------------------------------
* NOTE: How to save a wad2 file:
*
* UInt32 count; - used by the saving routines
* WAD2DirPtr dir; - WAD2 directory structure (created step by step)
* UInt16 n; - number of entries in WAD2 directory (idem)
*
* WriteWAD2Header(f, &count, &dir, &n); - write the header
* size = WriteSomething(f, ...); - save one entry
* AddWAD2Entry(f, &count, &dir, &n, name, size, type); - add entry to dir.
* size = WriteSomethingElse(f, ...); - save another entry
* AddWAD2Entry(f, &count, &dir, &n, othername, size, type); - add to dir. too
* totalsize = WriteWAD2Directory(f, &count, dir, n); - write the directory
*/
/*
* Write the WAD2 header to the file. The header will be modified later,
* when the directory is written to the file.
*/
Bool WriteWAD2Header(FILE *wadfile, UInt32 *count_r, WAD2DirPtr *dir_r,
UInt16 *dirsize_r)
{
char buf[100];
sprintf(buf, "WAD2********\r\nQEU %s\r\n", QEU_VERSION);
if ((wadfile == NULL)
|| (WriteBytes(wadfile, buf, (UInt32)strlen(buf)) == FALSE))
return FALSE;
*dir_r = NULL;
*count_r = (UInt32)strlen(buf);
*dirsize_r = 0;
return TRUE;
}
/*
* Add a new entry to the WAD2 directory. This entry should have been
* saved previously and be "entrysize" bytes long. It will be stored
* in the WAD2 directory under the name "entryname".
* All object saving routines in this package return the number of bytes
* written, so that number can be passed directly to this routine.
*/
Bool AddWAD2Entry(FILE *wadfile, UInt32 *count_r, WAD2DirPtr *dir_r,
UInt16 *dirsize_r, char *entryname, UInt32 entrysize,
UInt8 entrytype)
{
UInt16 n;
UInt32 compressedsize;
char buf[17];
if (wadfile == NULL || *count_r == 0L)
return FALSE;
n = *dirsize_r;
if (n == 0)
*dir_r = (WAD2DirPtr)QMalloc((UInt32)sizeof(struct WAD2Directory));
else
*dir_r = (WAD2DirPtr)QRealloc(*dir_r, (UInt32)(n + 1)
* (UInt32)sizeof(struct WAD2Directory));
compressedsize = entrysize; /* don't know how to compress, so... */
strncpy(buf, entryname, 16);
buf[16] = '\0';
QStrNCpy((*dir_r)[n].name, strupr(buf), 16);
(*dir_r)[n].offset = *count_r;
(*dir_r)[n].size = compressedsize;
(*dir_r)[n].dsize = entrysize;
(*dir_r)[n].dtype = entrytype;
(*dir_r)[n].compression = 0;
(*dir_r)[n].padding = 0;
*count_r = *count_r + compressedsize;
*dirsize_r = n + 1;
return TRUE;
}
/*
* Write the WAD2 directory to the file. This should only be done
* after all entries have been saved (using the appropriate
* Write... routine) and registered (using AddWAD2Entry). The WAD2
* header is updated so that it points to the directory.
*
* This routine returns the total number of bytes taken by the WAD2
* file (header + all entries + directory). It is thus possible to
* include a WAD2 file in another WAD2 file or in a PACK file.
*/
UInt32 WriteWAD2Directory(FILE *wadfile, UInt32 *count_r, WAD2DirPtr dir,
UInt16 dirsize)
{
UInt32 size, pos;
UInt16 i;
pos = *count_r;
if (wadfile == NULL || pos == 0L)
return 0L;
*count_r = 0L; /* invalidate the counter */
size = (UInt32)dirsize;
if ((fseek(wadfile, 4L - (Int32)(pos), SEEK_CUR) < 0)
|| (WriteInt32(wadfile, &size) == FALSE)
|| (WriteInt32(wadfile, &pos) == FALSE)
|| (fseek(wadfile, (Int32)(pos) - 12L, SEEK_CUR) < 0))
return 0L;
for (i = 0; i < dirsize; i++)
if ((WriteInt32(wadfile, &(dir[i].offset)) == FALSE)
|| (WriteInt32(wadfile, &(dir[i].size)) == FALSE)
|| (WriteInt32(wadfile, &(dir[i].dsize)) == FALSE)
|| (WriteBytes(wadfile, &(dir[i].dtype), 20L) == FALSE))
return 0L;
return size * (UInt32)sizeof(struct WAD2Directory) + pos;
}
/* end of file */